package com.snow.useviewdemo.function2.camera

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.util.Size
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.common.util.concurrent.ListenableFuture
import com.snow.common.tool.utils.ToastUtils
import com.snow.useviewdemo.R
import com.snow.useviewdemo.base.BaseKotlinActivity
import com.snow.useviewdemo.util.HandlerHelper
import kotlinx.android.synthetic.main.activity_camerax.*
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.EnumSet.of
import java.util.List.of
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
 * Created by zhyt
 * Date: 2022/8/23
 * Describe:适配 5.0(21)及以上版本 拍照片、拍视频
 */
@SuppressLint("RestrictedApi")
class CameraXActivity : BaseKotlinActivity() {
    private lateinit var imageCapture: ImageCapture
    private lateinit var outputDirectory: File
    private lateinit var cameraExecutor: ExecutorService
    private lateinit var videoCapture: VideoCapture
    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
    private var isRecordingVideo: Boolean = false

    override fun getLayoutId(): Int {
        return R.layout.activity_camerax
    }

    override fun setViewData(savedInstanceState: Bundle?) {
        if (allPermissionsGranted()) {
            openCamera()
        } else {
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        }
        camera_capture_button.setOnClickListener {
            takePhoto()
        }
        camera_capture_button2.setOnClickListener {
            if (isRecordingVideo) {
                stopRecordVideo()
            } else {
                takeVideo()
            }
        }
        outputDirectory = getOutputDirectory()
        cameraExecutor = Executors.newSingleThreadExecutor()
    }

    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture ?: return
        // Create time-stamped output file to hold the image
        val photoFile = File(
            outputDirectory,
            SimpleDateFormat(
                FILENAME_FORMAT, Locale.US
            ).format(System.currentTimeMillis()) + ".jpg"
        )
        // Create output options object which contains file + metadata
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
        // Set up image capture listener, which is triggered after photo has
        // been taken
        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this),
            object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo capture succeeded: $savedUri"
                    ToastUtils.getInstance().showToast(msg)
                    Log.d(TAG, msg)
                }
            })
    }

    private fun takeVideo() {
        //视频保存路径
        val file = File(
            outputDirectory,
            SimpleDateFormat(
                FILENAME_FORMAT, Locale.US
            ).format(System.currentTimeMillis()) + ".mp4"
        )
        //开始录像
        isRecordingVideo = true
        ToastUtils.getInstance().showToast("start recording")
//        val outputFileOptions = VideoCapture.OutputFileOptions.Builder(file).build()
        videoCapture.startRecording(
            file,
            Executors.newSingleThreadExecutor(),
            object : VideoCapture.OnVideoSavedCallback {

                override fun onVideoSaved(file: File) {
                    //保存视频成功回调，会在停止录制时被调用
                    HandlerHelper.post {
                        ToastUtils.getInstance().showToast(file.absolutePath)
                    }
                    val msg = "video capture succeeded: " + file.absolutePath
                    Log.d(TAG, msg)
                }

                override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
                    //保存失败的回调，可能在开始或结束录制时被调用
                    Log.e("", "onError: $message")
                }
            })
    }


    private fun stopRecordVideo() {
        videoCapture.stopRecording()
        isRecordingVideo = false
    }

    private fun openCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
//            bindPicPreview()
            bindVideoPreview()
        }, ContextCompat.getMainExecutor(this))
    }

    /**
     * 绑定拍照片的预览
     */
    private fun bindPicPreview() {
        // Used to bind the lifecycle of cameras to the lifecycle owner
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        // Preview
        val preview = Preview.Builder()
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.createSurfaceProvider())
            }
        imageCapture = ImageCapture.Builder().build()
        val imageAnalyzer = ImageAnalysis.Builder()
            .build()
            .also {
                it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                    Log.d(TAG, "Average luminosity: $luma").toDouble()
                })
            }
        // Select back camera as a default
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
        try {
            // Unbind use cases before rebinding
            cameraProvider.unbindAll()
            // Bind use cases to camera
            cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageCapture, imageAnalyzer
            )
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }

    /**
     * 绑定拍视频的预览
     */
    private fun bindVideoPreview() {
        val preview = Preview.Builder()
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.createSurfaceProvider())
            }
        val cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
//                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
            .build()
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        videoCapture = VideoCapture.Builder()
            .setBitRate(1024 * 1024)//设置视频的比特率
            .setVideoFrameRate(36)//设置视频的帧率
            .setTargetRotation(preview.targetRotation)//设置相机的旋转角度
            .setAudioBitRate(1024)//设置音频的码率
            .setTargetResolution(Size(720, 1080))//设置生成的视频的分辨率
            .build()
        cameraProvider.bindToLifecycle(
            this,
            cameraSelector,
            videoCapture,
            preview
        )
    }

    private fun getOutputDirectory(): File {
        val mediaDir =
            externalMediaDirs.firstOrNull()?.let { File(it, "snowTestDemo").apply { mkdirs() } }
        return if (mediaDir != null && mediaDir.exists())
            mediaDir else filesDir
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                openCamera()
            } else {
                ToastUtils.getInstance().showToast("Permissions not granted by the user.")
                finish()
            }
        }
    }

    companion object {
        private const val TAG = "CameraXBasic"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    }
}